package vip.xiaonuo.modular.vxpay.controller;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpStatus;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import com.google.gson.Gson;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import org.jdom.Document;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import vip.xiaonuo.core.exception.ServiceException;
import vip.xiaonuo.core.pojo.response.ResponseData;
import vip.xiaonuo.core.pojo.response.SuccessResponseData;
import vip.xiaonuo.core.util.HttpRequest;
import vip.xiaonuo.modular.user.entity.User;
import vip.xiaonuo.modular.user.service.UserService;
import vip.xiaonuo.modular.usertrace.entity.UserTrace;
import vip.xiaonuo.modular.usertrace.service.UserTraceService;
import vip.xiaonuo.modular.vxpay.model.PayModel;
import vip.xiaonuo.modular.vxpay.model.PayRequestBodyVo;
import vip.xiaonuo.modular.vxpay.model.WxUserInfo;
import vip.xiaonuo.modular.vxpay.util.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.StringReader;
import java.math.BigDecimal;
import java.util.*;

import static vip.xiaonuo.modular.vxpay.service.PaymentService.*;
import static vip.xiaonuo.modular.vxpay.service.PaymentService.APPID;
import static vip.xiaonuo.modular.vxpay.service.PaymentService.createSign;
import static vip.xiaonuo.modular.vxpay.service.PaymentService.doXMLParse;

@Api(tags = "微信相关接口")
@RestController("weChat")
public class WeChatPayController {

    private   Logger logger =  LoggerFactory.getLogger(getClass());
    @Autowired
    private UserService userService;

    @Autowired
    private UserTraceService userTraceService;

    @Autowired
    private WxPayService payService;


    /*@RequestMapping(value = "/payment", method = {RequestMethod.POST})
    @ApiOperation("微信支付")
    @ResponseBody
    public SortedMap<Object, Object> WapSignSignatureAction(@RequestBody PayModel payModel,HttpServletRequest request) throws Exception {
        SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();

        // code作为换取access_token的票据，每次用户授权带上的code将不一样，code只能使用一次，5分钟未被使用自动过期。
        // 通过code换取网页授权access_token
        String grant_type = "authorization_code";
        //1、向微信服务器 使用登录凭证 code 获取 session_key 和 openid
        //请求参数
        String params = "appid=" + APPID + "&secret=" + AppSecret + "&js_code=" + payModel.getCode() + "&grant_type=" + grant_type;
        //发送请求
        String sr = HttpRequest.sendGet("https://api.weixin.qq.com/sns/jscode2session");
        //解析相应内容（转换成json对象）
        com.alibaba.fastjson.JSONObject json = com.alibaba.fastjson.JSONObject.parseObject(sr);
        //获取会话密钥（session_key）
        String session_key = json.get("session_key").toString();
        //用户的唯一标识（openid）
        String openid = (String) json.get("openid");
        String nonce_str = create_nonce_str();
        String timestamp = create_timestamp();
        // 获取prepayId
        try {
            String result = getPrepayId(request, payModel.getTName(), WeiXinUtil.generateOrderNo(), payModel.getTotalFee(), openid);
            Map<String, String> map = doXMLParse(result);
            // 重新生成签名
            parameters.put("appId", APPID);
            parameters.put("timeStamp", timestamp);
            parameters.put("nonceStr", nonce_str);
            parameters.put("package", "prepay_id=" + map.get("prepay_id"));
            parameters.put("signType", "MD5");
            String sign = createSign("UTF-8", parameters);
            parameters.put("prepay_id", "prepay_id=" + map.get("prepay_id"));
            parameters.put("paySign", sign);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return parameters;
    }


    @ApiOperation("微信支付，预下单")
    @PostMapping("/pay")
    public SuccessResponseData wxpay(@RequestBody PayRequestBodyVo vo) {
        try {
            String unifiedorder = WeiXinUtil.getUnifiedorder(vo.getOpenid(), vo.getOutTradeNo(), Double.valueOf(vo.getSumValue()));
            Map<String, String> map = WeiXinUtil.doXMLParse(unifiedorder);
            SortedMap<Object, Object> param = WeiXinUtil.prepayId(map);
            return new SuccessResponseData(param);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new SuccessResponseData();
    }*/

    /**
     * 客户端返回JSON字符串
     *
     * @param response
     * @param object
     * @return
     */
    protected String renderString(HttpServletResponse response, Object object) {
        return renderString(response, new Gson().toJson(object), "application/json");
    }

    /**
     * 客户端返回字符串
     *
     * @param response
     * @param string
     * @return
     */
    protected String renderString(HttpServletResponse response, String string, String type) {
        try {
            response.reset();
            response.setContentType(type);
            response.setCharacterEncoding("utf-8");
            //解决跨域问题
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.getWriter().print(string);
            return null;
        } catch (IOException e) {
            return null;
        }
    }

    /**
     * 返回前台H5调用JS支付所需要的参数，小程序支付调用此接口
     *
     * @param response
     * @param request
     */
    @ApiOperation("返回前台H5调用JS支付所需要的参数，小程序支付调用此接口")
    @RequestMapping(value = "getJSSDKPayInfo",method = RequestMethod.POST)
    public void getJSSDKPayInfo(HttpServletResponse response,
                                HttpServletRequest request) {
        ReturnModel returnModel = new ReturnModel();
        WxPayUnifiedOrderRequest prepayInfo = WxPayUnifiedOrderRequest.newBuilder()
                .openid(request.getParameter("openid"))
                .outTradeNo(request.getParameter("out_trade_no"))
                .totalFee(Integer.valueOf(request.getParameter("total_fee")))
                .body(request.getParameter("body"))
                .tradeType(request.getParameter("trade_type"))
                .spbillCreateIp(request.getParameter("spbill_create_ip"))
                .notifyUrl("https://www.xiongxiaoji.com/api/getJSSDKCallbackData")
                .build();

        try {
            Map<String, String> payInfo = payService.getPayInfo(prepayInfo);
            returnModel.setResult(true);
            returnModel.setDatum(payInfo);
            renderString(response, returnModel);
        } catch (WxPayException e) {
            returnModel.setResult(false);
            returnModel.setReason(e.getErrCodeDes());
            renderString(response, returnModel);
        }
    }

    /**
     * 微信通知支付结果的回调地址，notify_url
     *
     * @param request
     * @param response
     */
    @RequestMapping(value = "getJSSDKCallbackData",method = RequestMethod.GET)
    public void getJSSDKCallbackData(HttpServletRequest request,
                                     HttpServletResponse response) {
        try {
            synchronized (this) {
                Map<String, String> kvm = XMLUtil.parseRequestXmlToMap(request);
                if (SignUtils.checkSign(kvm, null, "jH17BDg0kv24IKctSzasX30HeZbE0sgo")) {
                    if (kvm.get("result_code").equals("SUCCESS")) {
                        //TODO(user) 微信服务器通知此回调接口支付成功后，通知给业务系统做处理
                        logger.info("out_trade_no: " + kvm.get("out_trade_no") + " pay SUCCESS!");
                        response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[ok]]></return_msg></xml>");
                    } else {
                        this.logger.error("out_trade_no: "
                                + kvm.get("out_trade_no") + " result_code is FAIL");
                        response.getWriter().write(
                                "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[result_code is FAIL]]></return_msg></xml>");
                    }
                } else {
                    response.getWriter().write(
                            "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[check signature FAIL]]></return_msg></xml>");
                    this.logger.error("out_trade_no: " + kvm.get("out_trade_no")
                            + " check signature FAIL");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    //提现到零钱
    //https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
    @PostMapping("/transfer")
    @ApiOperation("提现")
    @ResponseBody
    public ResponseData transfer(@RequestBody Map<String,String> map ) throws JDOMException, IOException {
        String openid = map.get("openid");
        String amount = map.get("amount");
        logger.debug("提现申请额度:{}",amount);
        User user = userService.searchByOpenId(openid);
        if (ObjectUtil.isEmpty(user))
            throw new ServiceException(HttpStatus.HTTP_NOT_FOUND,"用户不存在");
        BigDecimal subtract = user.getWithdrawOver().subtract(new BigDecimal(amount));
        if (Integer.valueOf(subtract.toString()) < 0)
            throw new ServiceException(HttpStatus.HTTP_INTERNAL_ERROR,"可提现金额超出当前申请提现金额");
        String transfers = doTransfers(openid, new BigDecimal(amount));
        if (!transfers.contains("CDATA[FAIL]")) {
            //修改金额
            user.setWithdrawOver(subtract);
            userService.updateById(user);
            //生成流水
            UserTrace userTrace = new UserTrace();
            userTrace.setUserId(user.getId());
            userTrace.setAddTime(new Date());
            userTrace.setAmount(new BigDecimal(amount));
            userTrace.setType(2);
            userTrace.setSource(2);
            userTrace.setMsg("微信余额");
            userTrace.setPhone(user.getPhone());
            userTrace.setTraceSn("提现");
            //保存流水
            userTraceService.save(userTrace);
        }else {
            SAXBuilder saxBuilder = new SAXBuilder();
            Document doc = saxBuilder.build(new StringReader(transfers));
            return  new SuccessResponseData(doc.getRootElement().getChild("err_code_des").getValue());
        }
        return new SuccessResponseData(transfers);

    }

    /**
     * 根据微信code获取openId,session_key
     * @param params
     * @return
     */
    @ApiOperation("根据微信code获取openId,session_key")
    @PostMapping("/wxLogin")
    public ResponseData login(@RequestBody Map params) {
        String code= params.get("code").toString();//也可以通过此语句获取code值
        Map res = new HashMap();//这里是自定义类，用于封装返回的数据，你可以用map替代
        Map map = WeiXinUtil.getOpenid(code);
        System.out.println(map);
        System.out.println("用户的openid为：" + map.get("openid"));//此处也可以得到session_key的值
        String openid = map.get("openid").toString();
        res.put("openid", openid);
        res.put("session_key",map.get("session_key"));
        return new SuccessResponseData(res);
    }


    @ApiOperation("获取用户信息")
    @PostMapping("/getWxUserInfo")
    public ResponseData getWxUserInfo(@RequestBody Map params) {
        String sessionKey = params.get("session_key").toString();
        String encrypted= params.get("encrypdata").toString();//也可以通过此语句获取code值
        String iv= params.get("iv").toString();//
        String data =  WeiXinUtil.wxDecrypt(encrypted,sessionKey,iv);
        JSONObject object = JSONObject.parseObject(data);
        WxUserInfo wxUserInfo = new WxUserInfo();
        wxUserInfo.setNickName(object.getString("nickName"));
        wxUserInfo.setAvatarUrl(object.getString("avatarUrl"));
        wxUserInfo.setCountry(object.getString("country"));
        wxUserInfo.setCity(object.getString("city"));
        wxUserInfo.setProvince(object.getString("province"));
        wxUserInfo.setGender(object.getInteger("gender"));
        logger.debug("微信信息：{}",wxUserInfo);
        return new SuccessResponseData(wxUserInfo);
    }

    @SneakyThrows
    @ApiOperation("获取手机号")
    @PostMapping("/getUserPhoneNumber")
    public ResponseData getUserPhoneNumber(@RequestBody Map params) {
        String sessionKey = params.get("session_key").toString();
        String encrypted= params.get("encrypdata").toString();//也可以通过此语句获取code值
        String iv= params.get("iv").toString();//
        String data =  WeiXinUtil.decryptNew(encrypted,sessionKey,iv);
        data = new String(data.getBytes("UTF-8"));
        System.out.println(data);
        JSONObject object = JSONObject.parseObject(data);
        Map<String, Object> map = object.getInnerMap();
        logger.debug("手机解析信息：{}",object);
        if (map.containsKey("phoneNumber")){
            String phoneNumber = map.get("phoneNumber").toString();
            logger.debug("手机：{}",phoneNumber);
            return new SuccessResponseData(phoneNumber);
        }
        return new SuccessResponseData();
    }



}
